#pragma once

#include <iostream>
#include <cstring>

// 模板参数列表中有默认参数，指定MaxLength为int类型，调用时可以不用显示指定MaxLength类型
template<class QueueElem, int MaxLength>
class CircleQueue
{
private:
    // 队列被初始化的标志，true 已被初始化
    bool m_init;   
    // 数组储存循环队列中的元素
    QueueElem m_data[MaxLength];
    // 头指针
    int m_head;
    // 尾指针
    int m_tail;
    // 队列的实际长度
    int m_length;

    // 禁用拷贝构造函数
    CircleQueue(const CircleQueue &) = delete;

    // 禁用赋值函数
    CircleQueue &operator=(const CircleQueue &) = delete;
public:
    CircleQueue()
    {
        this->init();
    }

    ~CircleQueue()
    {}

    // 循环队列的初始化
    // 注：如果用于共享内存的队列，不会调用构造函数，必须手动调用此函数初始化
    void init()
    {
        if (!this->m_init)  // 初始化只一次
        {
            this->m_head = 0;
            this->m_tail = MaxLength - 1;
            this->m_length = 0;
            // 数组元素清0
            memset(this->m_data, 0, sizeof(this->m_data));
            this->m_init = true;
        }
    }

    // 判断队列是否为空
    bool is_empty()
    {
        return this->m_length == 0;
    }

    // 判断队列是否已满
    bool is_full()
    {
        return this->m_length >= MaxLength;
    }
    
    // 元素入队，返回插入结果
    bool push(const QueueElem & elem)
    {
        if (this->is_full())
        {
            std::cout << "队列已满，插入失败" << std::endl;
            return false;
        }
        // 先移动队尾指针，再拷贝元素
        this->m_tail = (this->m_tail+1)%MaxLength;
        this->m_data[this->m_tail] = elem;
        this->m_length++;
        return true;
    }

    // 元素出队，返回出队结果
    bool pop()
    {
        if (this->is_empty())
        {
            std::cout << "队列为空" << std::endl;
            return false;
        }
        // 移动队头指针
        this->m_head = (this->m_head+1)%MaxLength;
        this->m_length--;
    }

    // 返回队列长度
    int size()
    {
        return this->m_length;
    }

    // 查看队列头元素
    QueueElem& head()
    {
        return this->m_data[this->m_head];
    }

    // 查看队列尾元素
    QueueElem& tail()
    {
        return this->m_data[this->m_tail];
    }

    // 打印队列中元素
    void print_queue()
    {
        for (int i = 0; i < this->m_length; i++)
        {
            std::cout << "m_data[" << (this->m_head+i)%MaxLength << "]=" << this->m_data[(this->m_head+i)%MaxLength] << std::endl;
        }
        
    }
};



